package tileStyle;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * Executor stores the queue of tiles that need to be "executed".
 *  
 * @author 					<a href=mailto:jaeyounb@usc.edu>Jae young Bang</a>
 * @version 				2014.06
 *
 */
public class Executor {
	
///////////////////////////////////////////////
// Member Variables
///////////////////////////////////////////////
	
	/**
	 * Queue that stores the tiles that need to be executed
	 */
	private BlockingQueue<Tile> 	queue 		= new ArrayBlockingQueue<Tile>(10000);
	
	/**
	 * Looping thread that monitors the queue and executes incoming tiles
	 */
	private ExecutorLooper			looper;
	
///////////////////////////////////////////////
// Constructors
///////////////////////////////////////////////
	
	/**
	 * Default constructor
	 * 
	 * @param parentNode			Parent node
	 */
	public Executor (Node parentNode) {
		// initializes the looper
		looper 		= new ExecutorLooper(parentNode);	
	}
	
///////////////////////////////////////////////
// Member Methods
///////////////////////////////////////////////
	
	/**
	 * Starts the executor loop
	 */
	public void start () {
		// starts the looper
		looper.start();
	}
	
	/**
	 * Adds a new tile to the queue
	 * @param tile			Tile to be executed
	 */
	public void add (Tile tile) {
		try {
			queue.put(tile);
		} catch (InterruptedException e) {
			// do nothing
		}
	}
	
	/**
	 * Gets the size of the queue
	 * 
	 * @return				Size of the queue
	 */
	public int size () {
		return queue.size();
	}
	
	/**
	 * ExecutorLooper constantly monitors the queue. When there is a new tile
	 * added to the queue, ExecutorLooper pops the tile and executes it. 
	 */
	public class ExecutorLooper extends Thread {
		
		/**
		 * Parent node
		 */
		private Node parentNode;
		
		/**
		 * Default constructor
		 * @param parentNode		Parent node
		 */
		public ExecutorLooper (Node parentNode) {
			this.parentNode = parentNode;
		}
		
		/**
		 * Monitors the queue. Executes every tile added to the queue.
		 */
		public void run () {
			while(true) {
				try {
					// takes the head of the queue
					Tile tile = queue.take();
					
					Tile returnTile = parentNode.executeTile(tile); 
					// executes the tile
					if(returnTile != null) {
						// puts the tile back into the queue if it needs to be put back
						queue.put(returnTile);
					}
					
				} catch (InterruptedException e) {
					// do nothing
				}
			}
		}
	}
}
